package centerberg.game;

import centerberg.engine.Camera;
import centerberg.engine.Drawable;
import centerberg.engine.Engine;
import centerberg.engine.GameObject;
import centerberg.engine.PhysicsObject;
import centerberg.engine.Texture;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.LinkedList;

/**
 * Class representing a level in the game along with all
 * the objects in it. Also keeps track of the name and
 * bounds of the level. In addition to this it is also
 * responsible for drawing the level timer.
 * 
 * @author Andreas Svanberg
 */
public class Level
{
    private Collection<GameObject> gameObjects = new LinkedList<GameObject>();
    private long time;
    private Timer timer;
    private int left, right;
    private String name;
    
    /**
     * Creates a new level with the given name and
     * bounding x-axises.
     * 
     * @param name  name of the level
     * @param left  left x-axis bounding the level
     * @param right right x-axis bounding the level
     */
    public Level(String name, int left, int right)
    {
        this.name = name;
        this.left = left;
        this.right = right;
    }
    
    /**
     * Adds an object to this level.
     * 
     * @param object object to add
     */
    public void addObject(GameObject object)
    {
        gameObjects.add(object);
    }
    
    /**
     * Returns the left bounding x-axis
     * 
     * @return the left bounding x-axis
     */
    public int getLeft()
    {
        return left;
    }
    
    /**
     * Returns the right bounding x-axis
     * 
     * @return the right bounding x-axis
     */
    public int getRight()
    {
        return right;
    }
    
    /**
     * Starts the level by adding all the objects to the
     * engine and then starting it. If it detects a camera
     * object it also creates a timer object for drawing
     * the time spend on the level.
     */
    public void start()
    {
        Engine engine = Engine.getInstance();
        
        for (GameObject obj : gameObjects)
        {
            if (obj instanceof PhysicsObject)
                engine.physics.addToWorld( (PhysicsObject)obj );
            
            if (obj instanceof Camera)
            {
                timer = new Timer( (Camera)obj );
                engine.add(timer);
            }
            
            engine.add(obj);
        }
        
        Game.currentLevel = this;
        time = 0;
        
        engine.run();
    }
    
    /**
     * Called when the level is won.
     */
    public void victory()
    {
        Engine.getInstance().stop();
        MenuSystem.showMenu(new VictoryMenu(name, time));
    }
    
    /**
     * Timer for drawing the time on screen. Relies on a
     * camera to provide fixed position on the screen.
     */
    private class Timer extends GameObject implements Drawable
    {
        private Camera camera;
        
        private Timer(Camera camera)
        {
            this.camera = camera;
        }
        
        public Texture getTexture()
        {
            BufferedImage img = new BufferedImage(120, 24, BufferedImage.TYPE_INT_ARGB);
            Graphics g = img.getGraphics();
            
            // calculate the correct translation coordinates based on where the camera is looking
            int x = 680 + camera.getViewport().x;
            int y = 000 + camera.getViewport().y;
            
            g.setColor(java.awt.Color.GREEN);
            g.setFont(g.getFont().deriveFont(20f));
            g.drawString(String.format("Time: %d'%01ds", Level.this.time / 1000, Level.this.time % 1000 / 100), 0, 24);
            
            Texture t = new Texture(img, 60, 24);
            t.translate(x, y);
            return t;
        }
        
        public void tick(double elapsed)
        {
            Level.this.time += elapsed;
        }
    }
}